package com.hfzy.ihk.web.linkcall.biz.KnowledgeBase;

import com.alibaba.fastjson.JSON;
import com.hfzy.ihk.common.constants.GlobalStatic;
import com.hfzy.ihk.common.core.elasticsearch.EsQueryUtils;
import com.hfzy.ihk.common.core.elasticsearch.base.BestDoContextHolder;
import com.hfzy.ihk.common.core.elasticsearch.service.EsBaseServiceImpl;
import com.hfzy.ihk.common.util.Utils;
import com.hfzy.ihk.common.util.string.StringUtil;
import com.hfzy.ihk.common.util.uuid.base64uuid.UUIDs;
import com.hfzy.ihk.common.web.WebResult;
import com.hfzy.ihk.facade.linkcall.entity.flow.config.SpeakingPackage;
import com.hfzy.ihk.facade.linkcall.entity.knowledge.KnowledgeBase;
import com.hfzy.ihk.facade.linkcall.enums.AffectType;
import com.hfzy.ihk.facade.linkcall.enums.AfterAnswerOptionalType;
import com.hfzy.ihk.facade.linkcall.enums.AnswerType;
import com.hfzy.ihk.facade.linkcall.enums.KnowledgeBase.KnowledgeBaseRedisVersionKey;
import com.hfzy.ihk.facade.linkcall.enums.KnowledgeBase.KnowledgeBaseTables;
import com.hfzy.ihk.facade.linkcall.enums.KnowledgeType;
import com.hfzy.ihk.facade.linkcall.vo.KnowledgeBaseResultVo;
import com.hfzy.ihk.facade.linkcall.vo.knowledgeBase.KnowledgeBaseVo;
import com.hfzy.ihk.web.linkcall.biz.flow.config.SpeakingFlowBiz;
import com.hfzy.ihk.web.linkcall.biz.flow.config.SpeakingPackageBiz;
import com.hfzy.ihk.web.linkcall.dao.KnowledgeBaseRepository;
import com.hfzy.ihk.web.linkcall.support.annotation.PreProcessParam;
import com.hfzy.ihk.web.linkcall.support.annotation.PushMsgToAIService;
import com.hfzy.ihk.web.linkcall.utils.LayUiParamUtils;
import com.hfzy.ihk.web.linkcall.utils.UserUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * 操作知识库的Biz(业务逻辑)
 */
@Service
public class KnowledgeBaseBiz extends EsBaseServiceImpl<KnowledgeBase> {

    Logger logger = LoggerFactory.getLogger(KnowledgeBaseBiz.class);
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private KnowledgeBaseRepository knowledgeBaseRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private SpeakingFlowBiz speakingFlowBiz;

    @Autowired
    private SpeakingPackageBiz speakingPackageBiz;

    @Override
    protected ElasticsearchCrudRepository getReposity() {

        return knowledgeBaseRepository;
    }


    /**
     * 功能描述: es查询,返回Page对象
     *
     * @param: [searchQuery]
     * @return: org.springframework.data.domain.Page<com.hfzy.ihk.facade.linkcall.entity.knowledge.KnowledgeBase>
     * @auther:
     * @date: 2018/8/14
     */
    public Page<KnowledgeBase> esSearch(SearchQuery searchQuery) {


        Page<KnowledgeBase> page = knowledgeBaseRepository.search(searchQuery);

        return page;
    }


    /**
     * 功能描述:返回全部KnowledgeBase
     *
     * @param: []
     * @return: org.springframework.data.domain.Page<com.hfzy.ihk.facade.linkcall.entity.knowledge.QuestionBase>
     * @auther:
     * @date: 2018/8/14
     */
    public Page<KnowledgeBase> esSearchAllQuestionBase() {

        NativeSearchQuery search = new NativeSearchQueryBuilder().
                withQuery(EsQueryUtils.matchAllQuerty())
                .withPageable(PageRequest.of(0, 50))
                .build();

        Page<KnowledgeBase> page = knowledgeBaseRepository.search(search);

        return page;
    }

    ;


    /**
     * 功能描述:返回条件查询的list集合
     *
     * @param: [searchQuery]
     * @return: java.util.List<com.hfzy.ihk.facade.linkcall.entity.knowledge.KnowledgeBase>
     * @auther:
     * @date: 2018/8/14
     */
    public List<KnowledgeBase> esSearchForList(QueryBuilder queryBuilder) {

        /*//这个方法默认查10条,太坑爹了
        List<KnowledgeBase> list = elasticsearchTemplate.queryForList(searchQuery, KnowledgeBase.class);*/

        List<KnowledgeBase> list = new ArrayList<>();

        Iterator<KnowledgeBase> iterator = knowledgeBaseRepository.search(queryBuilder).iterator();

        if (iterator != null) {

            while (iterator.hasNext()) {

                KnowledgeBase next = iterator.next();
                list.add(next);
            }

        }
        return list;
    }


    //es局部更新
    @PushMsgToAIService
    public boolean updateSomeFields(String dataId, Class entityClass, Map<String, Object> fieldValueMap) {


        knowledgeBaseRepository.updateSomeFields(dataId, entityClass, fieldValueMap);

        return true;
    }


    /**
     * 根据字段更新
     *
     * @param knowledgeBaseVo
     * @return
     */
    public WebResult esUpdate(KnowledgeBaseVo knowledgeBaseVo) {

        WebResult result = new WebResult();

        try {
            if(!Utils.isNullString(knowledgeBaseVo.getRefPackageId())){//将该数据 复制生成新的知识库
                return esInsert(knowledgeBaseVo);
            }
            //调用方法局部更新
            boolean flag = esUpdateSomeFiled(knowledgeBaseVo);

            result.setCode(GlobalStatic.CODE_1);
            result.setMsg("更新成功!");

            /*if (!flag) {

                result.setCode(GlobalStatic.CODE_0);
                result.setMsg("服务器正忙呢,请稍后再试");
            }*/

            return result;

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("更新出错", e);
            result.setCode(GlobalStatic.CODE_0);
            result.setMsg("服务器正忙呢,请稍后再试");
            return result;
        }


    }

    /**
     * 功能描述: 新增保存
     *
     * @param: [knowledgeBaseVo ]
     * @return:WebResult
     * @auther:
     * @date: 2018/8/6
     */
    public WebResult esInsert(KnowledgeBaseVo knowledgeBaseVo) {
        logger.info("新增知识库:"+ JSON.toJSONString(knowledgeBaseVo));
        //返回结果集
        WebResult result = new WebResult();

        Map<String, Object> paramMap = new HashMap<>();

        try {
            KnowledgeBase knowledgeBase = new KnowledgeBase();
            //将Vo属性复制到实体类
            setVoToEntity(knowledgeBaseVo, knowledgeBase);

            //取得事务ID
            // String txId = BestDoContextHolder.getTransactionId();

            // boolean status = knowledgeBaseService.insert(knowledgeBase);

            //在此之前确保逻辑都正确执行
            //boolean flag = esAdd(knowledgeBase);
            if(knowledgeBase.getAffectType()==null){
                knowledgeBase.setAffectType(AffectType.PRIVATE);
            }
            knowledgeBase.setCreateUserId(UserUtils.getCurrentUserId()!=null?UserUtils.getCurrentUserId():0l);
            //切面未执行，通过这个来获取代理的对象执行插入操作
            ((KnowledgeBaseBiz)AopContext.currentProxy()).baseInsert(knowledgeBase);

            result.setMsg("保存成功");
            result.setCode(GlobalStatic.CODE_1);

            paramMap.put("id", knowledgeBase.getId());

            result.setParameter(paramMap);
           /* if (!flag) {
                logger.error("保存异常");
                result.setMsg("服务器正忙,请稍后重试");
                result.setCode(GlobalStatic.CODE_0);

            }*/
            return result;

        } catch (Exception e) {

            logger.error("保存异常", e);
            result.setMsg("服务器正忙,请稍后重试");
            if (e.getMessage().equals("此标题刚刚已经被使用了")){
                result.setMsg("此标题刚刚已经被使用了");
            };
            result.setCode(GlobalStatic.CODE_0);
            result.setParameter(null);

            return result;
        }
    }

    /**
     * 确保推送情况 以及数据完整性，增加一层基础类 通过此方法再到insert
     * */
    @PushMsgToAIService
    public boolean baseInsert(KnowledgeBase knowledgeBase){
        return insert(knowledgeBase);
    }


    /**
     * 功能描述:根据ID删除单个用户
     *
     * @param: [id : 需要删除的对象ID]
     * @return: boolean :删除是否成功
     * @auther:
     * @date: 2018/8/6
     */
    @PushMsgToAIService
    public WebResult esDeleteById(String id) {
        //封装结果集
        WebResult result = new WebResult();

        try {
            if (StringUtil.isNotNull(id)) {
                KnowledgeBase knowledgeBase = selectById(id);
                deleteById(id);

                if (knowledgeBase.getKeyworlds() != null && !knowledgeBase.getKeyworlds().isEmpty()) {
                    for (String keyword : knowledgeBase.getKeyworlds()) {//移除该知识库所绑定的关键词
                        redisTemplate.opsForSet().remove(knowledgeBase.getPackageId(), keyword);
                    }
                }
                result.setMsg("删除成功");
                result.setParameter(id);
                result.setCode(GlobalStatic.CODE_1);
                return result;
            }
            result.setMsg("删除人ID不能为空");
            result.setCode(GlobalStatic.CODE_0);
            return result;
        } catch (Exception e) {
            logger.error("删除异常", e);
            result.setMsg("服务器正忙,请稍后重试");
            result.setCode(GlobalStatic.CODE_0);
            return result;
        }

    }

    /**
     * 功能描述:根据ID查询单个用户
     *
     * @param: [id]
     * @return:
     * @auther:
     * @date: 2018/8/6
     */
    public WebResult esSelectById(String id) {

        //封装结果集
        WebResult result = new WebResult();

        try {
            if (StringUtil.isNotNull(id)) {

                KnowledgeBase knowledgeBase = selectById(id);

                result.setParameter(knowledgeBase);

                result.setMsg("查询成功");
                result.setCode(GlobalStatic.CODE_1);

                return result;
            }


            result.setMsg("查询ID不能为空");
            result.setCode(GlobalStatic.CODE_0);
            return result;
        } catch (Exception e) {
            logger.error("根据ID查询异常", e);
            result.setMsg("服务器正忙请稍后重试");
            result.setCode(GlobalStatic.CODE_0);
            return result;
        }

    }


    /**
     * 功能描述: 分页查询
     *
     * @param: [
     * key : 查询关键字
     * page :当前页
     * limit:每页大小
     * ]
     * @auther:
     * @return: 用于封装layui所需的结果
     * @date: 2018/8/7
     */
    @PreProcessParam
    public Map<String, Object> queryKnowledgeBaseBySearch(Map<String, String> paramMap, ModelAndView model) {


        try {

            //用于封装查询条件
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

            paramMap.forEach((key, value) -> {

                switch (key) {

                    case "key":

                        if (StringUtil.isNotNull(value)) {//当用户输入标题
                            model.addObject("KnowledgeBaseKeyword", value);
                            EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.wildcardQuery("title", "*" + value + "*"));
                        }

                        break;
                    case "packageId":

                        if (StringUtil.isNotNull(value)) {
                            EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.termQuery("packageId", value));
                        }

                        break;

                    case "knowledgeType":

                        if (StringUtil.isNotNull(value)) {
                            EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.termQuery("knowledgeType", KnowledgeType.fromValue(value).name()));
                        }

                        break;

                    case "keyworld":

                        if (StringUtil.isNotNull(value)) {
                            EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.wildcardQuery("keyworlds", value));
                        }
                        break;
                    case "affectType":
                        if(StringUtil.isNotNull(value)){
                            EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.termQuery("affectType", AffectType.fromValue(value).name()));
                        }
                        break;
                    case "howAskQuestion":
                        if(StringUtil.isNotNull(value)){
                            EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.wildcardQuery("howAskQuestions.keyword", "*"+value+"*"));
                        }
                        break;
                    case "createUserId":
                        if(StringUtil.isNotNull(value)){
                            EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.termQuery("createUserId", value));
                        }
                        break;

                }

            });

            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(queryBuilder)
                    //按修改时间降序
                    .withSort(SortBuilders.fieldSort("modTime").order(SortOrder.DESC))
                    //用于分页
                    .withPageable(PageRequest.of(Integer.parseInt(paramMap.get("page")) - 1, Integer.parseInt(paramMap.get("limit")))).build();

            Page<KnowledgeBase> pageSearch = esSearch(searchQuery);

            //注入相关属性
            if(paramMap.containsKey("refPackageId") && !Utils.isNullString(paramMap.get("refPackageId"))){//如果有指定的话术包
                injectionsAttr(pageSearch.getContent(),paramMap.get("refPackageId"));
            }
            //工具类封装layui表格所需参数
            Map<String, Object> resultMap = LayUiParamUtils.getInstance().toLayuiTableMap(pageSearch);

            return resultMap;

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("查询列表错误", e);
            Map<String, Object> errorMap = new HashMap<>();
            errorMap.put("code", "1");//状态码,0代表成功.切记
            errorMap.put("msg", "目前访问人数过多,请稍后重试");
            errorMap.put("count", null);
            errorMap.put("data", null);
            return errorMap;
        }


    }
    /*public Map<String, Object> queryKnowledgeBaseBySearch(String key, Integer page, Integer limit, String packageId ,String keyworld,String knowledgeType, ModelAndView model) {


        try {

            //用于封装查询条件
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

            if(StringUtil.isNotNull(key) || StringUtil.isNotNull(packageId) || StringUtil.isNotNull(knowledgeType)){
                if (StringUtil.isNotNull(key)) {//当用户输入关键字
                    model.addObject("KnowledgeBaseKeyword", key);
                    EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.wildcardQuery("title", "*" + key + "*"));
                }
                if (StringUtil.isNotNull(packageId)) {
                    EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.termQuery("packageId", packageId));
                }
                if (StringUtil.isNotNull(knowledgeType)){
                    EsQueryUtils.boolQuery(queryBuilder, EsQueryUtils.BoolType.MUST, QueryBuilders.termQuery("knowledgeType", KnowledgeType.fromValue(knowledgeType).name()));
                }
            }
            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(queryBuilder)
                    //按修改时间降序
                    .withSort(SortBuilders.fieldSort("modTime").order(SortOrder.DESC))
                    //用于分页
                    .withPageable(PageRequest.of(page - 1, limit)).build();

            Page<KnowledgeBase> pageSearch = esSearch(searchQuery);

            //工具类封装layui表格所需参数
            Map<String, Object> resultMap = LayUiParamUtils.getInstance().toLayuiTableMap(pageSearch);
            return resultMap;

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("查询列表错误", e);
            Map<String, Object> errorMap = new HashMap<>();
            errorMap.put("code", "1");//状态码,0代表成功.切记
            errorMap.put("msg", "目前访问人数过多,请稍后重试");
            errorMap.put("count", null);
            errorMap.put("data", null);
            return errorMap;
        }


    }*/


    /**
     * 功能描述:es新增一条KnowledgeBase并进行版本维护
     *
     * @param: [knowledgeBase]
     * @return: boolean
     * @auther:
     * @date: 2018/8/14
     */
    @PushMsgToAIService
    public boolean esAdd(KnowledgeBase knowledgeBase) {

        if (knowledgeBase != null) {
            if(knowledgeBase.getAffectType()==null){
                knowledgeBase.setAffectType(AffectType.PRIVATE);
            }
            boolean flag = createDataAndSetVersion(KnowledgeBaseRedisVersionKey.TABLE_KNOWLEDGEBASE,
                    KnowledgeBaseTables.KNOWLEDGEBASE,
                    knowledgeBase.getId(),
                    knowledgeBase.getVersion(),
                    () -> insert(knowledgeBase));
            return flag;
        }
        return false;
    }

    /**
     * 功能描述:es局部更新
     *
     * @param: [knowledgeBaseVo]
     * @return: boolean
     * @auther:
     * @date: 2018/8/16
     */
    public boolean  esUpdateSomeFiled(KnowledgeBaseVo knowledgeBaseVo) {

        logger.info("根据字段更新知识库:"+ JSON.toJSONString(knowledgeBaseVo));

        //此map封装需要修改的属性
        Map<String, Object> fields = new HashMap<>();

        //对关键词去重
//        distinctKeywords(knowledgeBaseVo);
        filterEmptyKeywords(knowledgeBaseVo);

        //对问法去重
        List<String> howAskQuestions = distinctHowAskQuestions(knowledgeBaseVo);

        if (distinctTitle(knowledgeBaseVo)){

            throw new RuntimeException("此标题刚刚已经被使用了");
        };

        //如果此属性为1,就是说明这是由小程序调用的接口
        if ("1".equals(knowledgeBaseVo.getFromApp())) {
            //封装属性
            fields.put("title", knowledgeBaseVo.getTitle());
            fields.put("knowledgeType", knowledgeBaseVo.getKnowledgeType());
            fields.put("keyworlds", knowledgeBaseVo.getKeyworlds());
            fields.put("oneToOneResult", knowledgeBaseVo.getOneToOneResult());
            fields.put("howAskQuestions", howAskQuestions);
            fields.put("answerType", knowledgeBaseVo.getAnswerType());
            fields.put("packageId", knowledgeBaseVo.getPackageId());
            fields.put("afterAnswerOptionalType", knowledgeBaseVo.getAfterAnswerOptionalType());
            fields.put("skipFlowId", knowledgeBaseVo.getSkipFlowId());
            fields.put("mutiSessionFlowId", knowledgeBaseVo.getMutiSessionFlowId());
            fields.put("actionCodeBreak", knowledgeBaseVo.isActionCodeBreak());
            fields.put("usageTypes", knowledgeBaseVo.getUsageTypes());
            fields.put("affectType",knowledgeBaseVo.getAffectType());
        } else {
            fields.put("actionCodeBreak", knowledgeBaseVo.isActionCodeBreak());

            //封装属性
            fields.put("title", knowledgeBaseVo.getTitle());
            fields.put("packageId", knowledgeBaseVo.getPackageId());
            fields.put("knowledgeType", knowledgeBaseVo.getKnowledgeType());
            fields.put("keyworlds", knowledgeBaseVo.getKeyworlds());
            fields.put("answerType", knowledgeBaseVo.getAnswerType());
            fields.put("oneToOneResult", knowledgeBaseVo.getOneToOneResult());
            fields.put("mutiSessionFlowId", knowledgeBaseVo.getMutiSessionFlowId());
            fields.put("skipFlowId", knowledgeBaseVo.getSkipFlowId());
            fields.put("afterAnswerOptionalType", knowledgeBaseVo.getAfterAnswerOptionalType());
            fields.put("usageTypes", knowledgeBaseVo.getUsageTypes());
            fields.put("modTime", new Date());
            fields.put("howAskQuestions", howAskQuestions);
            fields.put("affectType",knowledgeBaseVo.getAffectType());
            //假如是一对一,清空多轮会话属性
            if (knowledgeBaseVo.getAnswerType() == AnswerType.ONE_TO_ONE) {

                fields.put("mutiSessionFlowId", null);


            } else {//假如多轮会话,清空一对一属性

                fields.put("skipFlowId", null);
                fields.put("afterAnswerOptionalType", null);
                fields.put("oneToOneResult", null);
                fields.put("knowledgeBaseResultVos",null);

            }
        }

        //暂时有个bug,就是单句问答的时候,答后操作为null
        if (knowledgeBaseVo.getAfterAnswerOptionalType()==null&&knowledgeBaseVo.getAnswerType() == AnswerType.ONE_TO_ONE){

            logger.info("单句问答下答后操作为null,将答后操作设置为转跳到原流程=================="+knowledgeBaseVo.getFromApp());

            fields.put("afterAnswerOptionalType", AfterAnswerOptionalType.ORIGIN_FLOW);

        }

        // 查询数据本来的version
        KnowledgeBase knowledgeBase = selectById(knowledgeBaseVo.getId());

        //判断 knowledgeBaseResultVos 原先有没有 保证更新操作时，确保该集合的数据是完整的
        List<KnowledgeBaseResultVo> knowledgeBaseResultVos = new ArrayList<>();//原有的单句问答的对象集合
        List<KnowledgeBaseResultVo> newKnowledgeBaseResultVos = new ArrayList<>();//新的单句问答的对象集合
        if(knowledgeBase.getKnowledgeBaseResultVos()!=null && !knowledgeBase.getKnowledgeBaseResultVos().isEmpty()){
            knowledgeBaseResultVos = knowledgeBase.getKnowledgeBaseResultVos();
        }
        //对原有的 按id进行分类 存到map集合 ==> 方便后续的判断操作
        Map<String,List<KnowledgeBaseResultVo>> idMaps = knowledgeBaseResultVos.stream().collect(Collectors.groupingBy(KnowledgeBaseResultVo::getId));

        if(knowledgeBaseVo.getKnowledgeBaseResultVos()!=null && !knowledgeBaseVo.getKnowledgeBaseResultVos().isEmpty()){
            for(KnowledgeBaseResultVo resultVo : knowledgeBaseVo.getKnowledgeBaseResultVos()){
                if(Utils.isNullString(resultVo.getId())){ //判断id为空情况下，则为新增的
                    resultVo.setId(UUIDs.base64UUID());
                }else if(idMaps.containsKey(resultVo.getId())){ //判断id在集合中的，确保数据完整，将recordFileUrl 传递过去
                    KnowledgeBaseResultVo knowledgeBaseResultVo = Utils.getFirst(idMaps.get(resultVo.getId()));
                    resultVo.setRecordFileUrl(knowledgeBaseResultVo.getRecordFileUrl());
                }
                newKnowledgeBaseResultVos.add(resultVo);
            }
        }
        fields.put("knowledgeBaseResultVos",newKnowledgeBaseResultVos);
        fields.put("version", knowledgeBase.getVersion() + 1L);


        //获取事务ID
        // String txId = BestDoContextHolder.getTransactionId();
        // knowledgeBaseService.esUpdate(knowledgeBaseVo.getId(), KnowledgeBase.class, fields);


        //在此之前确保逻辑都正确执行
        /*return checkVersionAndUpdateData(KnowledgeBaseRedisVersionKey.TABLE_KNOWLEDGEBASE,
                KnowledgeBaseTables.KNOWLEDGEBASE,
                knowledgeBaseVo.getId(),
                version,
                () -> updateSomeFields(knowledgeBaseVo.getId(), KnowledgeBase.class, fields));*/


        /**
         * 使用此次做法，是由于我们现在要切入到本类方法中较为底层保存数据结果的方法
         * ==>所以在调用时，需要通过 调用当前线程中的KnowledgeBaseBiz的代理类 来调用方法
         *    通过原本的this调用，是不会被切点切入
         * */
        boolean flag = ((KnowledgeBaseBiz) AopContext.currentProxy()).updateSomeFields(knowledgeBaseVo.getId(), KnowledgeBase.class, fields);
        //
//        boolean flag = this.updateSomeFields(knowledgeBaseVo.getId(), KnowledgeBase.class, fields);

        return flag;
    }


    /**
     * 过滤非空
     * @param knowledgeBaseVo
     * */
    public void filterEmptyKeywords(KnowledgeBaseVo knowledgeBaseVo){
        if(knowledgeBaseVo.getKeyworlds()!=null && !knowledgeBaseVo.getKeyworlds().isEmpty()){
            knowledgeBaseVo.setKeyworlds(knowledgeBaseVo.getKeyworlds().stream().distinct().filter(s -> {
                return StringUtil.isNotNull(s);
            }).collect(toList()));
        }
    }

    /**
     * 对关键词去重
     *
     * @param knowledgeBaseVo
     */
    public void distinctKeywords(KnowledgeBaseVo knowledgeBaseVo) {
/*
        //保证统一话术包的关键词不能重复
        //从es查询出所有相同话术包的KnowledgeBase
        BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("packageId", knowledgeBaseVo.getPackageId()));
        //只有在更新状态下才有ID
        String id = knowledgeBaseVo.getId();
        if (id!=null){
            boolQueryBuilder.mustNot(QueryBuilders.matchPhraseQuery("id", id));
        }
        Iterator<KnowledgeBase> iterator = knowledgeBaseRepository.search(boolQueryBuilder).iterator();
        //同一话术包下所有关键词集合
        List<String> allKeywordList=new ArrayList<>();
        while (iterator.hasNext()){
            KnowledgeBase next = iterator.next();
            allKeywordList.addAll(next.getKeyworlds());
        }
        //先对本来的去重,再对所有的去重,OJBK!
        List<String> distinctCollect = knowledgeBaseVo.getKeyworlds().stream().distinct().filter(s -> {return StringUtil.isNotNull(s);}).collect(toList());
        distinctCollect.removeAll(allKeywordList);*/

        //通过 redis 来存储 packageid 为key 值的 关键词库 用于过滤重复
        List<String> keywords = knowledgeBaseVo.getKeyworlds(); // 新关键词===>传递过来的
        List<String> newKeywords = new ArrayList<String>();
        if (keywords != null && !keywords.isEmpty()) {
            keywords = keywords.stream().filter(s -> {
                return StringUtil.isNotNull(s);
            }).collect(toList());
            for (String keyword : keywords) {
                long successNum = redisTemplate.opsForSet().add(knowledgeBaseVo.getPackageId(), keyword);//如果能够写入 则为新加入的关键词
                if (successNum > 0) {
                    newKeywords.add(keyword);
                }
            }
        }

        //如果是更新操作下
        if (!Utils.isNullString(knowledgeBaseVo.getId())) {
            KnowledgeBase knowledgeBase = selectById(knowledgeBaseVo.getId()); //判断之前的关键词
            if (knowledgeBase.getKeyworlds() != null && !knowledgeBase.getKeyworlds().isEmpty()) {
                if (keywords != null && !keywords.isEmpty()) {
                    for (String oldKeyword : knowledgeBase.getKeyworlds()) {
                        if (!keywords.contains(oldKeyword)) {//将 新关键词 和 原关键词对比， 过滤掉被删掉的
                            redisTemplate.opsForSet().remove(knowledgeBaseVo.getPackageId(), oldKeyword);//将被删掉的关键词 在 redis 词库中删除
                        } else {
                            newKeywords.add(oldKeyword);
                        }
                    }
                } else {
                    Arrays.stream(knowledgeBase.getKeyworlds().toArray(new String[knowledgeBase.getKeyworlds().size()])).forEach(it->{
                        redisTemplate.opsForSet().remove(knowledgeBaseVo.getPackageId(), it);//将被删掉的关键词 在 redis 词库中删除
                    });
                }

            }
        }

        knowledgeBaseVo.setKeyworlds(newKeywords.stream().distinct().filter(s -> {
            return StringUtil.isNotNull(s);
        }).collect(toList()));
    }

    /**
     * 对问法去重
     *
     * @param knowledgeBaseVo
     * @return
     */
    public List<String> distinctHowAskQuestions(KnowledgeBaseVo knowledgeBaseVo) {

        String regex = "([?.!;？。！；]+)*$";

        List<String> howAskQuestions = new ArrayList<String>();//用于储存传上来的问法

        List<String> allHowAskQuestion = new ArrayList<String>();//用于储存已重复的问法

        List<String> newHowAskQuestions = new ArrayList<>();//最终返回的问法list

        //如果此项属性为1,说明这是由小程序所调用的接口
        //
        if ("1".equals(knowledgeBaseVo.getFromApp())) {

            howAskQuestions = knowledgeBaseVo.getHowAskQuestionsForApp();

        } else {
            //取出问题先
            String questions = knowledgeBaseVo.getHowAskQuestions();

            //分割字符串,转为list
            howAskQuestions = splitString(questions, "[\"\\n\"]+");
        }

        Iterator<KnowledgeBase> iterator = getKnowledgeBaseByQueston(knowledgeBaseVo,howAskQuestions).iterator();

        while (iterator.hasNext()) {

            KnowledgeBase next = iterator.next();

            if (next.getHowAskQuestions() != null && !next.getHowAskQuestions().isEmpty()) {
                //去除最后的标点符号
               List<String> tempHowAskQuestions = next.getHowAskQuestions().stream().map(s -> s.replaceFirst(regex, "")).collect(toList());

                allHowAskQuestion.addAll(tempHowAskQuestions);//添加到重复问法的集合中
            }

        }

        if (howAskQuestions!=null&&!howAskQuestions.isEmpty()){
            newHowAskQuestions=howAskQuestions.stream().distinct().filter(s -> StringUtil.isNotNull(s)&&!allHowAskQuestion.contains(s.replaceFirst(regex,""))).collect(toList());
        }

        return newHowAskQuestions;
    }
    /*public List<String> distinctHowAskQuestions(KnowledgeBaseVo knowledgeBaseVo) {

        String regex = "[?.!;？。！；]+$";

        List<String> howAskQuestions = new ArrayList<String>();//用于储存传上来的问法

        List<String> allHowAskQuestion = new ArrayList<String>();//用于储存当前话术包下所有问法(是真实问法去掉最后的标点符号的问法)

        List<String> newHowAskQuestions = new ArrayList<>();//最终返回的问法list

        //如果此项属性为1,说明这是由小程序所调用的接口
        //
        if ("1".equals(knowledgeBaseVo.getFromApp())) {

            howAskQuestions = knowledgeBaseVo.getHowAskQuestionsForApp();

        } else {
            //取出问题先
            String questions = knowledgeBaseVo.getHowAskQuestions();

            //分割字符串,转为list
            howAskQuestions = splitString(questions, "[\"\\n\"]+");
        }

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (knowledgeBaseVo.getId() != null) {//假如ID不为空,证明这是修改,需要排除本来自身已经存在的问法

            boolQueryBuilder.mustNot(QueryBuilders.matchPhraseQuery("id", knowledgeBaseVo.getId()));
        }

        if (knowledgeBaseVo.getPackageId() != null) {//要求必须是同一话术包
            boolQueryBuilder.must(QueryBuilders.termQuery("packageId", knowledgeBaseVo.getPackageId()));
        }

        Iterator<KnowledgeBase> iterator = knowledgeBaseRepository.search(boolQueryBuilder).iterator();

        while (iterator.hasNext()) {

            KnowledgeBase next = iterator.next();

            if (next.getHowAskQuestions() != null && !next.getHowAskQuestions().isEmpty()) {
                //去除最后的标点符号
                List<String> tempHowAskQuestions = next.getHowAskQuestions().stream().map(s -> s.replaceFirst(regex, "")).collect(toList());

                allHowAskQuestion.addAll(tempHowAskQuestions);//添加到当前话术包所有问法的集合中
            }

        }

        if (howAskQuestions!=null&&!howAskQuestions.isEmpty()){
            newHowAskQuestions=howAskQuestions.stream().distinct().filter(s -> StringUtil.isNotNull(s)&&!allHowAskQuestion.contains(s.replaceFirst(regex,""))).collect(toList());
        }

        return newHowAskQuestions;
    }*/

    /**
     * 检测问法在话术包下是否已经存在(用es实现)
     *
     * @param knowledgeBaseVo
     * @return 对问法去重
     * @param knowledgeBaseVo
     * @return
     */
    public List<String> checkTheHowQuestion(KnowledgeBaseVo knowledgeBaseVo) {

        String regex = "([?.!;？。！；]+)*$";

        String fromApp = knowledgeBaseVo.getFromApp();//查看是否从小程序过来

        List<String> howAskQuestions = new ArrayList<String>();//用来储存传上来的问法

        List<String> allHowAskQuestions = new ArrayList<String>();//用来储存同一话术包下的所有问法(是真实问法去掉最后的标点符号的问法)

        List<String> existedHowAskQuestions = new ArrayList<String>();//用来存储重复的问法,将返回到前台

        if ("1".equals(fromApp)) {

            howAskQuestions = knowledgeBaseVo.getHowAskQuestionsForApp();
        } else {

            howAskQuestions = splitString(knowledgeBaseVo.getHowAskQuestions(), "[\"\\n\"]+");
        }

        if (howAskQuestions != null && !howAskQuestions.isEmpty()) {

            Iterator<KnowledgeBase> iterator = getKnowledgeBaseByQueston(knowledgeBaseVo,howAskQuestions).iterator();

            while (iterator.hasNext()) {

                KnowledgeBase next = iterator.next();
                List<String> temp = next.getHowAskQuestions();
                if (temp != null && !temp.isEmpty()) {
                    allHowAskQuestions.addAll(temp.stream().map(s -> s.replaceFirst(regex,"")).collect(toList()));
                }
            }

            for (String howAskQuestion : howAskQuestions) {

                if (allHowAskQuestions.contains(howAskQuestion.replaceFirst(regex,""))) {
                    existedHowAskQuestions.add(howAskQuestion);
                }
            }
        }
            return existedHowAskQuestions;
    }
   /* public List<String> checkTheHowQuestion(KnowledgeBaseVo knowledgeBaseVo) {

        String regex = "[?.!;？。！；]+$";

        String fromApp = knowledgeBaseVo.getFromApp();//查看是否从小程序过来

        List<String> howAskQuestions = new ArrayList<String>();//用来储存传上来的问法

        List<String> allHowAskQuestions = new ArrayList<String>();//用来储存同一话术包下的所有问法(是真实问法去掉最后的标点符号的问法)

        List<String> existedHowAskQuestions = new ArrayList<String>();//用来存储重复的问法,将返回到前台

        if ("1".equals(fromApp)) {

            howAskQuestions = knowledgeBaseVo.getHowAskQuestionsForApp();
        } else {

            howAskQuestions = splitString(knowledgeBaseVo.getHowAskQuestions(), "[\"\\n\"]+");
        }

        if (howAskQuestions != null && !howAskQuestions.isEmpty()) {

            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            if (knowledgeBaseVo.getId() != null) {
                boolQueryBuilder.mustNot(QueryBuilders.matchPhraseQuery("id", knowledgeBaseVo.getId()));
            }
            boolQueryBuilder.must(QueryBuilders.termQuery("packageId", knowledgeBaseVo.getPackageId()));

            Iterator<KnowledgeBase> iterator = knowledgeBaseRepository.search(boolQueryBuilder).iterator();

            while (iterator.hasNext()) {

                KnowledgeBase next = iterator.next();
                List<String> temp = next.getHowAskQuestions();
                if (temp != null && !temp.isEmpty()) {
                    allHowAskQuestions.addAll(temp.stream().map(s -> s.replaceFirst(regex,"")).collect(toList()));
                }
            }

            for (String howAskQuestion : howAskQuestions) {

                if (allHowAskQuestions.contains(howAskQuestion.replaceFirst(regex,""))) {
                    existedHowAskQuestions.add(howAskQuestion);
                }
            }
        }

        return existedHowAskQuestions;
    }*/


    /**
     * 功能描述:根据传入参数查找
     *
     * @param: [paramMap]
     * @return: java.util.List<com.hfzy.ihk.facade.linkcall.entity.knowledge.KnowledgeBase>
     * @auther:
     * @date: 2018/8/20
     */
    @PreProcessParam
    public List<KnowledgeBase> searchKnowledgeBaseByField(Map<String, String> paramMap) {

        List<KnowledgeBase> knowledgeBases = null;
        try {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            //NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

            if (paramMap == null || paramMap.size() == 0) {

                boolQueryBuilder.must(EsQueryUtils.matchAllQuerty());

            }
            if (paramMap.containsKey("title")) {

                boolQueryBuilder.must(EsQueryUtils.wildcardQuery("title", "*" + paramMap.get("title") + "*"));
            }

            //根据输入标题精确查找,用于前台页面校验输入的标题是否已经存在
            if (paramMap.containsKey("termTitle")) {

                boolQueryBuilder.must(EsQueryUtils.termQuery("title", paramMap.get("termTitle")));
            }

            if (paramMap.containsKey("id")) {

                boolQueryBuilder.must(EsQueryUtils.termQuery("id.keyword", paramMap.get("id")));
            }

            if (paramMap.containsKey("packageId")) {

                boolQueryBuilder.must(QueryBuilders.termQuery("packageId", paramMap.get("packageId")));
            }
            if (paramMap.containsKey("createUserId")) {
                boolQueryBuilder.must(QueryBuilders.termQuery("createUserId", paramMap.get("createUserId")));
            }
            if (paramMap.containsKey("titles")) {
                boolQueryBuilder.must(QueryBuilders.termsQuery("title", paramMap.get("titles").split(",")));
            }
            if (paramMap.containsKey("affectType")) {
                boolQueryBuilder.must(QueryBuilders.termQuery("affectType", AffectType.fromValue(paramMap.get("affectType")).name()));
            }

            if (paramMap.containsKey("affectTypeNull")) {
                boolQueryBuilder.mustNot(QueryBuilders.rangeQuery("affectType").gt(1));
            }
           /* nativeSearchQueryBuilder.withQuery(boolQueryBuilder);

            NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();*/

            knowledgeBases = esSearchForList(boolQueryBuilder);

            //注入相关属性
            if(paramMap.containsKey("refPackageId") && !Utils.isNullString(paramMap.get("refPackageId"))){//如果有指定的话术包
                injectionsAttr(knowledgeBases,paramMap.get("refPackageId"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return knowledgeBases;

    }


    // =================================华丽分割线,以下为自用方法======================================
    //将字符串分割为字符串数组
    private List<String> splitString(String questions, String reg) {

        if (StringUtil.isNotNull(questions)) {
            //分割为字符串数组,查看有没有不合法的字符,再返回筛选后的集合
            return Arrays.stream(questions.split(reg)).filter((a) -> StringUtil.isNotNull(a)).collect(toList());
        }

        return null;
    }


    /**
     * 将vo复制到entity
     */
    public void setVoToEntity(KnowledgeBaseVo knowledgeBaseVo, KnowledgeBase knowledgeBase) {
        //TODO ========== 覆盖原有的知识库内容 ==》产生新的知识记录
        if(knowledgeBaseVo.getAffectType()!=null){
            knowledgeBase.setAffectType(knowledgeBaseVo.getAffectType());
        }else{
            knowledgeBase.setAffectType(AffectType.PRIVATE);//没有传入指定类型的话，则当自定义处理
        }
        if(!Utils.isNullString(knowledgeBaseVo.getRefPackageId()) && !Utils.isNullString(knowledgeBaseVo.getId())){
            knowledgeBase.setPackageId(knowledgeBaseVo.getRefPackageId());
            knowledgeBase.setOverrideId(knowledgeBaseVo.getId());
            knowledgeBase.setAffectType(AffectType.PRIVATE);

            //并同时重置到 knowledgeBaseVo 上
            knowledgeBaseVo.setAffectType(AffectType.PRIVATE);
            knowledgeBaseVo.setPackageId(knowledgeBaseVo.getRefPackageId());
        }

        //对关键词去重
//        distinctKeywords(knowledgeBaseVo);
        filterEmptyKeywords(knowledgeBaseVo);

        //对标题去重,如果重复直接抛异常
        if (distinctTitle(knowledgeBaseVo)){

            throw  new  RuntimeException("此标题刚刚已经被使用了");
        }

        //暂时有个bug,就是单句问答的时候,答后操作为null
        if (knowledgeBaseVo.getAfterAnswerOptionalType()==null&&knowledgeBaseVo.getAnswerType() == AnswerType.ONE_TO_ONE){

            logger.info("单句问答下答后操作为null,将答后操作设置为转跳到原流程=================="+knowledgeBaseVo.getFromApp());

            knowledgeBaseVo.setAfterAnswerOptionalType(AfterAnswerOptionalType.ORIGIN_FLOW);

        }

        //copy属性
        BeanUtils.copyProperties(knowledgeBaseVo, knowledgeBase);

        //对问法去重
        List<String> howAskQuestions = distinctHowAskQuestions(knowledgeBaseVo);

        knowledgeBase.setHowAskQuestions(howAskQuestions);

        //假如选择单句问答,不保存多轮问答属性,如果选择多轮问答,不保存单句问答属性
        if (knowledgeBase.getAnswerType() == AnswerType.ONE_TO_ONE) {

            knowledgeBase.setMutiSessionFlowId(null);

        } else if (knowledgeBase.getAnswerType() == AnswerType.MUTI_SESSION) {

            knowledgeBase.setAfterAnswerOptionalType(null);

            knowledgeBase.setOneToOneResult(null);

            knowledgeBase.setSkipFlowId(null);

        }

        if (knowledgeBaseVo.getUsageTypes() != null && !knowledgeBaseVo.getUsageTypes().isEmpty()) {
            knowledgeBase.setUsageTypes(knowledgeBaseVo.getUsageTypes());
        }

        //封装Id
        knowledgeBase.setId(UUIDs.base64UUID());

        //User user = WebThreadContextHolder.getUser();

        //封装user,先写死
//        knowledgeBase.setCreateUserId(1888L);

        //封装创建时间

        Date now = new Date();

        knowledgeBase.setCreateTime(now);

        knowledgeBase.setModTime(now);

        /**
         * 单句问答对象集合
         * 如果id 是空时，则补填uuid
         * */
        knowledgeBaseVo.getKnowledgeBaseResultVos().forEach(it->{
            if(Utils.isNullString(it.getId())){
               it.setId(UUIDs.base64UUID());
            }
        });
        knowledgeBase.setKnowledgeBaseResultVos(knowledgeBaseVo.getKnowledgeBaseResultVos());

    }


    /**
     * 对标题去重,如果有重复直接抛出异常
     *
     * 如果检测到标题重复时，
     * @param knowledgeBaseVo
     */
    private boolean distinctTitle(KnowledgeBaseVo knowledgeBaseVo) {

        Map<String,String> paramMap=new HashMap<>();

        if (knowledgeBaseVo.getPackageId()!=null){

            paramMap.put("packageId",knowledgeBaseVo.getPackageId());
        }

        if (knowledgeBaseVo.getTitle()!=null){

            paramMap.put("termTitle",knowledgeBaseVo.getTitle());
        }

        List<KnowledgeBase> list = searchKnowledgeBaseByField(paramMap);
        
        if (list!=null&&!list.isEmpty()){
            list=list.stream().filter(knowledgeBase -> !knowledgeBase.getId().equals(knowledgeBaseVo.getId())).collect(toList());
            if (!list.isEmpty()){
                return true;
            }
        }

        return false;

    }

    @PreProcessParam
    public Page<KnowledgeBase> getKnowledgeBaseByPage(Map<String, String> params) {
        BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        int pageNum = Integer.valueOf(params.get("page")) - 1;
        int pageSize = Integer.valueOf(params.get("pageSize"));
        //添加排序字段
        FieldSortBuilder fieldSortBuilder = null;
        if (params.containsKey("orderByModeTime")) {
            fieldSortBuilder = SortBuilders.fieldSort("modTime").order(SortOrder.DESC);
        } else {
            fieldSortBuilder = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        }
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withSort(fieldSortBuilder).withPageable(PageRequest.of(pageNum, pageSize));
        Page<KnowledgeBase> page =  knowledgeBaseRepository.search(builder.build());
        //注入属性
        if(params.containsKey("refPackageId") && !Utils.isNullString(params.get("refPackageId"))){//如果有指定的话术包
            injectionsAttr(page.getContent(),params.get("refPackageId"));
        }
        return  page;
    }


    public BoolQueryBuilder getQueryBuilderByParams(Map<String, String> params) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Iterator entries = params.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry entry = (Map.Entry) entries.next();
            String key = entry.getKey().toString();
            switch (key) {
                case "createTimeStart":
                    boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", params.get("createTimeStart"),
                            null, true, false));
                    break;
                case "createTimeEnd":
                    boolQueryBuilder.must(EsQueryUtils.rangeQuery("createTime", null,
                            params.get("createTimeEnd"), false, true));
                    break;
                case "title":
                    boolQueryBuilder.must(EsQueryUtils.wildcardQuery("title", "*" + params.get("title") + "*"));
                    break;
                case "titles":
                    boolQueryBuilder.must(EsQueryUtils.termsQuery("title",params.get("titles").split(",")));
                    break;
                case "packageId":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("packageId", params.get("packageId")));
                    break;
                case "packageIds":
                    boolQueryBuilder.must(EsQueryUtils.termsQuery("packageId", params.get("packageIds").split(",")));
                    break;
                case "id":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("id.keyword", params.get("id")));
                    break;
                case "overrideIdNoEmpty":
                    boolQueryBuilder.must(QueryBuilders.existsQuery("overrideId"));
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("overrideId").gt(1));//长度大于1 ，为空的或者不存在的则过滤
                    break;
                case "affectType":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("affectType", AffectType.fromValue(params.get("affectType")).name()));
                    break;
                case "createUserId":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("createUserId", params.get("createUserId")));
                    break;
                case "afterAnswerOptionalType.keyword":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("afterAnswerOptionalType", AfterAnswerOptionalType.fromValue(params.get("afterAnswerOptionalType")).name()));
                    break;
                case "notExistsResultVo":
                    boolQueryBuilder.mustNot(QueryBuilders.existsQuery("knowledgeBaseResultVos"));
                    break;
                case "knowledgeType":
                    if (StringUtil.isNotNull(params.get("knowledgeType"))) {
                        boolQueryBuilder.must(EsQueryUtils.termQuery("knowledgeType", KnowledgeType.fromValue(params.get("knowledgeType")).name()));
                    }
                    break;
                default:
                    break;
            }
        }
        return boolQueryBuilder;
    }

    @PreProcessParam
    public List<KnowledgeBase> getKnowledgeBaseList(Map<String, String> params) {
        BoolQueryBuilder  boolQueryBuilder = getQueryBuilderByParams(params);
        List<KnowledgeBase> list = new ArrayList<>();
        Iterator<KnowledgeBase> iterator = knowledgeBaseRepository.search(boolQueryBuilder).iterator();
        if (iterator != null) {
            while (iterator.hasNext()) {
                KnowledgeBase next = iterator.next();
                list.add(next);
            }
        }
        //注入相关属性
        if(params.containsKey("refPackageId") && !Utils.isNullString(params.get("refPackageId"))){//如果有指定的话术包
            injectionsAttr(list,params.get("refPackageId"));
        }
        return list;
    }


    /**
     * 取出同一话术包下所有的关键词,用于小程序判断关键词是否重复
     *
     * @param params
     */
    public Set<String> getAllwords(Map<String, String> params) {

        if (params.containsKey("packageId")) {

            String packageId = params.get("packageId");

            Set<String> members = redisTemplate.opsForSet().members(packageId);

            if (members != null && !members.isEmpty()) {

                if (params.containsKey("id")){//有ID,代表是更新.需要去除本知识库本来存在的关键词

                    KnowledgeBase knowledgeBase = selectById(params.get("id"));

                    List<String> keyworlds = knowledgeBase.getKeyworlds();

                    if (keyworlds!=null&&!keyworlds.isEmpty()){

                        members.removeAll(keyworlds);
                    }

                }
                return members;
            }

        }
        return null;
    }

    /**
     * 取出同一话术包下所有的问法,用于小程序判断问法是否重复
     *
     * @param params
     */
    public List<String> getAllHowQuestions(Map<String, String> params) {

        List<String> questionList=new ArrayList<>();

        Map<String,String> paramMap=new HashMap<>();

        if (params.containsKey("packageId")) {

            paramMap.put("packageId",params.get("packageId"));

            List<KnowledgeBase> list = searchKnowledgeBaseByField(paramMap);

            if (list!=null&&!list.isEmpty()){

                if (params.containsKey("id")){//如果有ID,代表是更新,去除当前知识库的旧问法
                    list=list.stream().filter(knowledgeBase -> !knowledgeBase.getId().equals(params.get("id"))).collect(toList());
                }

                list.forEach(knowledgeBase -> {

                    if (knowledgeBase.getHowAskQuestions()!=null&&!knowledgeBase.getHowAskQuestions().isEmpty()){
                        questionList.addAll(knowledgeBase.getHowAskQuestions());
                    }

                });
            }
        }

        return questionList;
    }


    /**
     * 将所有知识库问法导入redis
     */
    public void importAllQuestionToRedis() {


        Iterator<KnowledgeBase> iterator = knowledgeBaseRepository.search(QueryBuilders.matchAllQuery()).iterator();

        while (iterator.hasNext()) {
            KnowledgeBase next = iterator.next();

            List<String> howAskQuestions = next.getHowAskQuestions();

            if (howAskQuestions != null && !howAskQuestions.isEmpty()) {

                for (String howAskQuestion : howAskQuestions) {

                    if (StringUtil.isNotNull(howAskQuestion)) {
                        redisTemplate.opsForSet().add(next.getPackageId() + "_howAskQuestions", howAskQuestion);
                    }
                }

            }
        }

    }


    public boolean addKnowledgeBases(List<String> titleList, List<KnowledgeBase> knowledgeBases){
        if(knowledgeBases==null || knowledgeBases.isEmpty()){
            return false;
        }
        List<KnowledgeBase> existsKnowledgeBases = new ArrayList<>(); //用于判断标题是否重复
        if(titleList==null || titleList.isEmpty()){
            titleList = knowledgeBases.stream().map(knowledgeBase -> knowledgeBase.getTitle()).collect(Collectors.toList());
        }

        /**
         * 查询条件不能大于1024
         * */
        String packageId = Utils.getFirst(knowledgeBases).getPackageId();
        List<String> titles = new ArrayList<>();
        for(int i= 0;i<titleList.size();i++){
            titles.add(titleList.get(i));
            if(titles!=null && !titles.isEmpty() && (titles.size()==1000 || i==titleList.size()-1)){
                Map map = new HashMap();
                map.put("packageId", packageId);
                map.put("titles", StringUtils.join(titles,","));
                List<KnowledgeBase> kbs = searchKnowledgeBaseByField(map);
                if(kbs!=null && !kbs.isEmpty()){
                    existsKnowledgeBases.addAll(kbs);
                }
                titles = new ArrayList<>();
            }
        }

        Map<String,List<KnowledgeBase>> existsMap = existsKnowledgeBases.stream().collect(Collectors.groupingBy(KnowledgeBase::getTitle));

        String txId = BestDoContextHolder.getTransactionId();
        Date date = new Date();
        List<KnowledgeBase> doKbs = new ArrayList<>();
        if (txId != null && knowledgeBases!=null && !knowledgeBases.isEmpty()) {//次要操作
            knowledgeBases.forEach(it -> {
                it.setId(org.elasticsearch.common.UUIDs.base64UUID());
                it.setCreateTime(date);
                it.setModTime(date);
                it.setCreateUserId(UserUtils.getCurrentUserId()!=null?UserUtils.getCurrentUserId():0l);

                //判断是否存在知识库 === 如果存在则进行合并操作
                if(existsMap.containsKey(it.getTitle())){
                    KnowledgeBase knowledgeBase = Utils.getFirst(existsMap.get(it.getTitle()));
                    if(knowledgeBase!=null){
                        //合并答案 ==
                        LinkedList<String> oneToOneResult = knowledgeBase.getOneToOneResult();
                        if(oneToOneResult==null){
                            oneToOneResult = it.getOneToOneResult();
                        }else if(it.getOneToOneResult()!=null && !it.getOneToOneResult().isEmpty()){
                            //格式化各自的 答案 用于对比时不需重复 操作
                            List<String> oldFilterStr= knowledgeBase.getOneToOneResult().stream().map(rs->StringUtil.stringFilter(rs)).collect(Collectors.toList());
                            Map<String,String> newAnswers = new HashMap();
                            it.getOneToOneResult().forEach(rs->{
                                newAnswers.put(StringUtil.stringFilter(rs),rs);
                            });

                            LinkedList<String> newRs = new LinkedList<String>();
                            newAnswers.entrySet().stream().forEach(entry->{
                                if(!oldFilterStr.contains(entry.getKey())){
                                    newRs.add(entry.getValue());
                                }
                            });
                            oneToOneResult.addAll(newRs);
                        }
                        if(oneToOneResult!=null && !oneToOneResult.isEmpty()){
                            List<KnowledgeBaseResultVo> resultVos = new ArrayList<>();
                            oneToOneResult.forEach(result->{
                                KnowledgeBaseResultVo knowledgeBaseResultVo = new KnowledgeBaseResultVo();
                                knowledgeBaseResultVo.setId(UUIDs.base64UUID());
                                knowledgeBaseResultVo.setContent(result);
                                knowledgeBaseResultVo.setRecordFileUrl("");
                                resultVos.add(knowledgeBaseResultVo);
                            });
                            knowledgeBase.setKnowledgeBaseResultVos(resultVos);
                            knowledgeBase.setOneToOneResult(oneToOneResult);
                        }

                        //合并关键字
                        if(it.getKeyworlds()!=null && !it.getKeyworlds().isEmpty()){
                            List<String> kws = knowledgeBase.getKeyworlds();
                            it.getKeyworlds().forEach(k->{
                                if(!kws.contains(k)){
                                    kws.add(k);
                                }
                            });
                            knowledgeBase.setKeyworlds(kws);
                        }
                        //问法暂时没有合并
                        knowledgeBase.setHowAskQuestions(it.getHowAskQuestions());
                        doKbs.add(knowledgeBase);
                    }
                }else{
                    doKbs.add(it);
                }
            });
            knowledgeBaseRepository.saveAll(doKbs);
            return true;
        }
        return false;
    }


    /**
     * 检测当前编辑的知识库是否属于所持有的公共知识库中
     * 如果持有则返回true
     *
     * 判断依据是？
     * 1、标题？
     * 2、关键词？
     * 3、问法？
     * */
    public boolean checkExistsInCommon(KnowledgeBase knowledgeBase){
        String packageId = knowledgeBase.getPackageId();
        boolean flag = false;
        if(!Utils.isNullString(packageId)){
            SpeakingPackage speakingPackage = speakingPackageBiz.getSpeakingPackageById(packageId);
            List<String> industryTypeIds = speakingPackage.getHadIndustryTypeId();
            if(industryTypeIds!=null && industryTypeIds.isEmpty()){
                //判断关键词是否一致
                outter:for (String typeId:industryTypeIds){
                    Set<String> members = redisTemplate.opsForSet().members(typeId);
                    inner:for (String keyword:knowledgeBase.getKeyworlds()){
                        if(members.contains(keyword)){
                            flag = true;
                            break outter;
                        }
                    }
                }
                //标题判断是否一致
                Map<String,String> params = new HashMap();
                params.put("title",knowledgeBase.getTitle());
                params.put("packageIds",knowledgeBase.getTitle());
                List<KnowledgeBase> knowledgeBases = getKnowledgeBaseList(params);

                if(knowledgeBases!=null && !knowledgeBases.isEmpty()){
                    flag = true;
                }else{
                    //TODO   判断问法是否一致 ====== 此处需要再修改
                    params = new HashMap();
                    params.put("howAskQuestions",Utils.getFirst(knowledgeBase.getHowAskQuestions()));
                    params.put("packageIds",knowledgeBase.getTitle());
                    knowledgeBases = getKnowledgeBaseList(params);
                    if(knowledgeBases!=null && !knowledgeBases.isEmpty()){
                        flag = true;
                    }
                }
            }
        }
        return flag;
    }

    /**
     * 对 packageId 下的 公共知识库 knowledgeBases 数据 注入属性 用于判断是否要可进行编辑的操作
     * @param  knowledgeBases 公共知识库
     * @param  packageId       话术包id
     * */
    public List<KnowledgeBase> injectionsAttr(List<KnowledgeBase> knowledgeBases,String packageId){
        try{
            if(knowledgeBases!=null && !knowledgeBases.isEmpty()){
                //返回 packageId 下的知识库 且 是进行替换公共知识库的 【即：overrideId 不为空】
                Map<String,String> conditionMap = new HashMap<String,String>();
                conditionMap.put("overrideIdNoEmpty","");
                conditionMap.put("packageId",packageId);
                conditionMap.put("affectType",AffectType.PRIVATE.getValue());
                List<KnowledgeBase> overrideKls = getKnowledgeBaseList(conditionMap);
                List<String>  overrideIds = overrideKls.stream().map(it->it.getOverrideId()).sorted().collect(Collectors.toList());

                knowledgeBases.stream().forEach(c->{
                    if(c.getAffectType()==AffectType.COMMON && overrideIds.contains(c.getId())){
                        c.setOverride(true);
                    }
                });
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error("加载指定话术包下的公共知识库注入相关属性异常 "+e.getMessage());
        }
        return knowledgeBases;
    }


    /**
     * 查询拥有相同问法的知识库
     * @param knowledgeBaseVo 封装了一些必须的参数
     * @param howAskQuestions 需要检测的问法集合
     * @return
     */
    public Iterable<KnowledgeBase> getKnowledgeBaseByQueston(KnowledgeBaseVo knowledgeBaseVo,List<String> howAskQuestions){

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //有ID,代表是更新知识库,将他排除
        if (knowledgeBaseVo.getId() != null) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery("id.keyword", knowledgeBaseVo.getId()));
        }

        //必须是相同话术包下
        boolQueryBuilder.must(QueryBuilders.termQuery("packageId", knowledgeBaseVo.getPackageId()));


        if (howAskQuestions!=null&&!howAskQuestions.isEmpty()){

            //问法集合每一句都是检测是否已存在,因此,用should
            BoolQueryBuilder shouldBoolQueryBuilder = QueryBuilders.boolQuery();

            for (String howAskQuestion : howAskQuestions) {

                shouldBoolQueryBuilder.should(QueryBuilders.regexpQuery("howAskQuestions.keyword", howAskQuestion.replaceFirst("([?.!;？。！；]+)*$","")+"[?.!;？。！；]*"));

            }

            boolQueryBuilder.must(shouldBoolQueryBuilder);
        }

        return  knowledgeBaseRepository.search(boolQueryBuilder);
    }

    /**
     * 根据条件返回对应的总数
     * */
    public long countKnowledgeBaseByField(Map<String, String> paramMap) {
        long count = 0;
        try {
            BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(paramMap);
            NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder);
            count = elasticsearchTemplate.count(builder.build(),KnowledgeBase.class);
        } catch (Exception e) {
            e.printStackTrace();
            count = 0;
        }
        return count;
    }

/**
 * 对问法去重
 *
 * @param knowledgeBaseVo
 * @return
 */
    /*public List<String> distinctHowAskQuestions(KnowledgeBaseVo knowledgeBaseVo) {

        String regex="[?.!;？。！；]+$";

        List<String> howAskQuestions = new ArrayList<String>();

        //如果此项属性为1,说明这是由小程序所调用的接口
        //
        if ("1".equals(knowledgeBaseVo.getFromApp())) {

            howAskQuestions = knowledgeBaseVo.getHowAskQuestionsForApp();

        } else {
            //取出问题先
            String questions = knowledgeBaseVo.getHowAskQuestions();

            //分割字符串,转为list
            howAskQuestions = splitString(questions, "[\"\\n\"]+");
        }

        List<String> newHowAskQuestions = new ArrayList<>();
        if (howAskQuestions != null && !howAskQuestions.isEmpty()) {
            //去掉空格
            howAskQuestions = howAskQuestions.stream().filter(s -> {
                return StringUtil.isNotNull(s);
            }).collect(toList());

            for (String howAskQuestion : howAskQuestions) {
                Long add = redisTemplate.opsForSet().add(knowledgeBaseVo.getPackageId() + "_howAskQuestions", howAskQuestion.replaceFirst(regex, ""));
                if (add > 0) {
                    newHowAskQuestions.add(howAskQuestion);
                }
            }
        }

        if (knowledgeBaseVo.getId() != null) {//id 不为空,代表是更新

            KnowledgeBase oldKnowledgeBase = selectById(knowledgeBaseVo.getId());
            List<String> oldHowAskQuestions = oldKnowledgeBase.getHowAskQuestions();
            if (oldHowAskQuestions != null && !oldHowAskQuestions.isEmpty()) {

                if (howAskQuestions != null && !howAskQuestions.isEmpty()) {
                    *//*for (String oldHowAskQuestion : oldHowAskQuestions) {
                        if (!howAskQuestions.contains(oldHowAskQuestion)) {
                            redisTemplate.opsForSet().remove(knowledgeBaseVo.getPackageId() + "_howAskQuestions", oldHowAskQuestion);
                        } else {
                            newHowAskQuestions.add(oldHowAskQuestion);
                        }
                    }*//*
                    for (String oldHowAskQuestion : oldHowAskQuestions) {
                        String tempOldHowAskQuestion = oldHowAskQuestion.replaceFirst(regex, "");

                        boolean flag = true;

                        for (String howAskQuestion : howAskQuestions) {

                            String temphowAskQuestion = howAskQuestion.replaceFirst(regex, "");

                            if (temphowAskQuestion.equals(tempOldHowAskQuestion)) {
                                newHowAskQuestions.add(oldHowAskQuestion);
                                flag = false;
                            }
                        }
                        if (flag) {
                            redisTemplate.opsForSet().remove(knowledgeBaseVo.getPackageId() + "_howAskQuestions", tempOldHowAskQuestion);
                        }
                    }
                } else {
                    redisTemplate.opsForSet().remove(knowledgeBaseVo.getPackageId() + "_howAskQuestions", oldHowAskQuestions.stream().map(s -> s.replaceFirst(regex, "")).collect(toList()).toArray(new String[oldHowAskQuestions.size()]));
                }
            }

        }

        return newHowAskQuestions.stream().distinct().filter(s -> {
            return StringUtil.isNotNull(s);
        }).collect(toList());
    }*/



    /**
     * 检测问法在话术包下是否已经存在(用redis实现)
     *
     * @param knowledgeBaseVo
     * @return
     */
    /*public List<String> checkTheHowQuestion(KnowledgeBaseVo knowledgeBaseVo) {

        String regex = "[?.!;？。！；]+$";//正则表达式,用于去除最后的标点

        String fromApp = knowledgeBaseVo.getFromApp();//查看是否从小程序过来

        List<String> howAskQuestions = new ArrayList<String>();//用来储存传上来的问法

        List<String> existedHowAskQuestions = new ArrayList<String>();//用来存储重复的问法,将返回到前台

        if ("1".equals(fromApp)) {

            howAskQuestions = knowledgeBaseVo.getHowAskQuestionsForApp();
        } else {

            howAskQuestions = splitString(knowledgeBaseVo.getHowAskQuestions(), "[\"\\n\"]+");
        }

        if (howAskQuestions != null && !howAskQuestions.isEmpty()) {

            for (String howAskQuestion : howAskQuestions) {

                String redisowAskQuestion = howAskQuestion.replaceFirst(regex, "");

                Boolean member = redisTemplate.opsForSet().isMember(knowledgeBaseVo.getPackageId() + "_howAskQuestions", redisowAskQuestion);

                if (member) {

                    existedHowAskQuestions.add(howAskQuestion);
                }
            }
        }

        if (knowledgeBaseVo.getId() != null && (howAskQuestions != null && !howAskQuestions.isEmpty())) {//假如有ID,代表是修改
            KnowledgeBase knowledgeBase = selectById(knowledgeBaseVo.getId());
            List<String> oldHowAskQuestions = knowledgeBase.getHowAskQuestions();
            *//*if (oldHowAskQuestions!=null&&!oldHowAskQuestions.isEmpty()){

                for (String oldHowAskQuestion : oldHowAskQuestions) {
                    if (howAskQuestions.contains(oldHowAskQuestion)){
                        existedHowAskQuestions.remove(oldHowAskQuestion);
                    }
                }
            }*//*
            if (oldHowAskQuestions != null && !oldHowAskQuestions.isEmpty()) {
                oldHowAskQuestions = oldHowAskQuestions.stream().map(s -> s.replaceFirst(regex, "")).collect(toList());
                for (String oldHowAskQuestion : oldHowAskQuestions) {
                    for (String howAskQuestion : howAskQuestions) {
                        String tempHowAskQuestion = howAskQuestion.replaceFirst(regex, "");
                        if (tempHowAskQuestion.equals(oldHowAskQuestion)) {
                            existedHowAskQuestions.remove(howAskQuestion);
                        }
                    }
                }
            }
        }

        return existedHowAskQuestions;
    }*/


}